﻿using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Think.Helpers;

namespace Think.Test.Helpers
{
    [TestClass]
    public class CollectionHelpersTest
    {
        [TestMethod]
        public void PushFirstIntoList()
        {
            // Setup
            var list = new [] { 1, 2, 3, 4 }.ToList();

            // Execute
            list.PushFirst(-5);

            // Assert
            CollectionAssert.AreEqual(new[] {-5, 1, 2, 3, 4}, list);
        }

        [TestMethod]
        [ExpectedException(typeof(NullReferenceException))]
        public void PushFirstIntoNullList()
        {
            // Setup
            var list = (IList<int>) null;

            // Execute
            list.PushFirst(-5);
        }

        [TestMethod]
        [ExpectedException(typeof(ArgumentNullException))]
        public void PushNullFirstIntoList()
        {
            // Setup
            var list = new[] {"1", "2", "3", "4"}.ToList();

            // Execute
            list.PushFirst(a_item:null);
        }

        [TestMethod]
        public void PushLastIntoList()
        {
            // Setup
            var list = new[] {"abc", "def", "ghi", "jkl"}.ToList();

            // Execute
            list.PushLast("mno");

            // Assert
            CollectionAssert.AreEqual(new[] { "abc", "def", "ghi", "jkl", "mno" }, list);
        }

        [TestMethod]
        [ExpectedException(typeof(NullReferenceException))]
        public void PushLastIntoNullList()
        {
            // Setup
            var list = (IList<string>)null;

            // Execute
            list.PushLast("mno");
        }

        [TestMethod]
        [ExpectedException(typeof(ArgumentNullException))]
        public void PushNullLastIntoList()
        {
            // Setup
            var list = new[] { "abc", "def", "ghi", "jkl" }.ToList();

            // Execute
            list.PushLast(a_item: null);
        }

        [TestMethod]
        public void PopFirstFromList()
        {
            // Setup
            var list = new[] {0.3, 0.6, 1.2, 2.4, 4.8}.ToList();


            // Execute
            var result = list.PopFirst();

            // Assert
            Assert.AreEqual(0.3, result);
            CollectionAssert.AreEqual(new[] {0.6, 1.2, 2.4, 4.8}, list);
        }

        [TestMethod]
        [ExpectedException(typeof(NullReferenceException))]
        public void PopFirstFromNullList()
        {
            // Setup
            var list = (IList<string>)null;

            // Execute
            var result = list.PopFirst();
        }

        [TestMethod]
        [ExpectedException(typeof(InvalidOperationException))]
        public void PopFirstFromEmptyList()
        {
            // Setup
            var list = new List<String>();

            // Execute
            var result = list.PopFirst();
        }

        [TestMethod]
        public void PopLastFromList()
        {
            var list = "Universe".ToList();

            // Execute
            var result = list.PopLast();

            // Assert
            Assert.AreEqual('e', result);
            CollectionAssert.AreEqual("Univers".ToList(), list);
        }

        [TestMethod]
        [ExpectedException(typeof(NullReferenceException))]
        public void PopLastFromNullList()
        {
            // Setup
            var list = (IList<char>)null;

            // Execute
            var result = list.PopLast();
        }

        [TestMethod]
        [ExpectedException(typeof(InvalidOperationException))]
        public void PopLastFromEmptyList()
        {
            // Setup
            var list = new List<char>();

            // Execute
            var result = list.PopLast();
        }

        [TestMethod]
        public void SplitListInValidPlace()
        {
            // Setup
            var list = "I am a monkey that does not like bananas.".Split(' ').ToList();

            // Execute
            var result = list.Split(4);

            // Assert
            CollectionAssert.AreEqual(new[] { "I", "am", "a", "monkey" }.ToList(), list);
            CollectionAssert.AreEqual(new[] { "that", "does", "not", "like", "bananas." }.ToList(), result);
        }

        [TestMethod]
        public void SplitListInLastPlace()
        {
            // Setup
            var list = new[] {99, 98, 97, 96}.ToList();

            // Execute
            var result = list.Split(3);

            // Assert
            CollectionAssert.AreEqual(new[] { 99, 98, 97 }.ToList(), list);
            CollectionAssert.AreEqual(new[] { 96 }.ToList(), result);
        }

        [TestMethod]
        public void SplitListInFirstPlace()
        {
            // Setup
            var list = new[] { '!', '@', '#', '$', '%', '^', '&', '*' }.ToList();

            // Execute
            var result = list.Split(0);

            // Assert
            Assert.IsFalse(list.Any());
            CollectionAssert.AreEqual(new[] { '!', '@', '#', '$', '%', '^', '&', '*' }.ToList(), result);
        }

        [TestMethod]
        [ExpectedException(typeof(ArgumentOutOfRangeException))]
        public void SplitListOutOfRange()
        {
            // Setup
            var list = new[] { 2, 4, 8, 16, 32, 64, 128, 256}.ToList();

            // Execute
            var result = list.Split(10);
        }

        [TestMethod]
        [ExpectedException(typeof(NullReferenceException))]
        public void SplitNullList()
        {
            // Setup
            List<Guid> list = null;

            // Execute
            list.Split(0);
        }

        [TestMethod]
        public void CheckValidIndexInRange()
        {
            // Setup
            var list = Enumerable.Repeat(3, 14).ToList();

            // Execute
            var result = list.InRange(7);

            // Assert
            Assert.IsTrue(result);
        }

        [TestMethod]
        public void CheckBadIndexInRange()
        {
            // Setup 
            var list = Enumerable.Repeat("Meow", 20).ToList();

            // Execute
            var result = list.InRange(20);

            // Assert
            Assert.IsFalse(result);
        }

        [TestMethod]
        public void CheckBadIndexInRangeOnEmptyList()
        {
            // Setup
            var list = new List<double>();

            // Execute
            var result = list.InRange(5);

            // Assert
            Assert.IsFalse(result);
        }

        [TestMethod]
        public void CheckNegativeIndexInRange()
        {
            // Setup 
            var list = Enumerable.Range(0, 2).ToList();

            // Execute
            var result = list.InRange(-1);

            // Assert
            Assert.IsFalse(result);        }

        [TestMethod]
        [ExpectedException(typeof(NullReferenceException))]
        public void CheckIndexInRangeOnNullList()
        {
            // Setup
            List<char> list = null;

            // Execute
            list.InRange(42);
        }
    }
}
